﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SceneLib
{
    public class SceneSphere : SceneObject
    {
        public Vector Center
        {
            get
            {
                return center;
            }
            set
            {
                center = value;
                Center0 = center.Copy();
            }
        }
        public float Radius { get; set; }
        public SceneMaterial Material { get; set; }
        public Vector Center0 { get; set; }

        private Vector center;

        public override Intersection Intersect(Vector e, Vector d, float t0, float tf, float time0, float timef)
        {
            Vector center0 = Center0 + time0 * Velocity;            
            center =  center0 + (time0 - timef) * Velocity;
            Vector centerF = center.Rotate(Rotation).Scale(Scale).Translate(Position);
            float discriminant = Vector.Dot3(d, e - centerF) * Vector.Dot3(d, e - centerF) - Vector.Dot3(d, d) * (Vector.Dot3(e - centerF, e - centerF) - Radius * Radius);
            Vector p = new Vector();
            Vector n = new Vector();

            if (discriminant < 0)
                return Intersection.NOINTERSECT;

            float t1 = (-Vector.Dot3(d, e - centerF) + Convert.ToSingle(Math.Sqrt(discriminant))) / (Vector.Dot3(d, d));
            float t2 = (-Vector.Dot3(d, e - centerF) - Convert.ToSingle(Math.Sqrt(discriminant))) / (Vector.Dot3(d, d));

            if (t1 < t0 || t1 > tf)
                if (t2 < t0 || t2 > tf)
                    return Intersection.NOINTERSECT;
                else
                {
                    p = e + d * t2;
                    n = p - centerF;
                    n.Normalize3();
                    if (Vector.Dot3(n, d) > 0)
                        n = -1f * n;

                    return new Intersection
                    {
                        IsIntersected = true,
                        T = t2,
                        Material = this.Material,
                        P = p,
                        Normal = n,
                        ObjectScene = this
                    };
                }
            else
                if (t2 < t0 || t2 > tf)
                {
                    p = e + d * t1;
                    n = p - centerF;
                    n.Normalize3();
                    if (Vector.Dot3(n, d) > 0)
                        n = -1f * n;

                    return new Intersection
                    {
                        IsIntersected = true,
                        T = t1,
                        Material = this.Material,
                        P = p,
                        Normal = n,
                        ObjectScene = this
                    };
                }
                else
                {
                    p = e + d * Math.Min(t1, t2);
                    n = p - centerF;
                    n.Normalize3();
                    if (Vector.Dot3(n, d) > 0)
                        n = -1f * n;

                    return new Intersection
                    {
                        IsIntersected = true,
                        T = Math.Min(t1, t2),
                        Material = this.Material,
                        P = p,
                        Normal = n,
                        ObjectScene = this                        
                    };
                }
        }

        public override Vector GetTextureColor(Vector p)
        {
            Vector centerF = center.Rotate(Rotation).Scale(Scale).Translate(Position);

            if (Material.TextureImage != null)
            {
                double phi = Math.Atan2(p.y - centerF.y, p.x - centerF.x);
                if (phi < 0)
                    phi += 2 * Math.PI;
                double thetha = Math.Acos(Math.Round((p.z - centerF.z) / Radius, 5));
                double u = phi / (2 * Math.PI);
                double v = (Math.PI - thetha) / Math.PI;
                int height = Material.TextureImage.Height;
                int width = Material.TextureImage.Width;
                float deltaU = Convert.ToSingle(u * (width - 1) - Math.Floor(u * (width - 1)));
                float deltaV = Convert.ToSingle(v * (height - 1) - Math.Floor(v * (height - 1)));                
                int i = Convert.ToInt32(Math.Floor(u * (width - 1)));
                int j = Convert.ToInt32(Math.Floor(v * (height - 1)));

                Vector color = (1 - deltaU) * (1 - deltaV) * Material.GetTexturePixelColor(i, j) +
                                deltaU * (1 - deltaV) * Material.GetTexturePixelColor((i + 1) % width, j) +
                                deltaV * (1 - deltaU) * Material.GetTexturePixelColor(i, (j + 1) % height) +
                                deltaV * deltaU * Material.GetTexturePixelColor((i + 1) % width, (j + 1) % height);

                return color;
            }
            else
                return new Vector(1, 1, 1);
            
        }
    }
}
